package howl.types;

import howl.model.Model;
import howl.model.PMF;
import howl.types.query.Result;
import howl.types.query.ResultSet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.users.User;



import compiler.exceptions.HowlModelException;
import compiler.terminals.BooleanExpression;
import compiler.terminals.OFTEN;
import compiler.terminals.TIMEUNIT;
import compiler.terminals.expression.Node;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Report {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id;

	@Persistent
	private User owner;

	@Persistent
	private String FeedName;

	@Persistent
	private byte[] exp;

	@Persistent
	private TIMEUNIT timeunit;
	
	@Persistent
	private OFTEN often;
	
	@Persistent
	private String when;
	
	@Persistent
	private Integer rate;

	private Date lastrun;


	public Report(Node exp) {
		super();
		this.lastrun = new Date();
		if(exp != null) {
		try {
			this.exp = Serializer.put(exp);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		} else {
			this.exp = null;
		}
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public User getOwner() {
		return owner;
	}

	public void setOwner(User owner) {
		this.owner = owner;
	}

	public Date getLastrun() {
		return lastrun;
	}

	public void setLastrun(Date lastrun) {
		this.lastrun = lastrun;
	}

	public String generateReport() throws HowlModelException, IOException,
			ClassNotFoundException {
		Model m = new Model(Model.getHowlUserfromUser(this.owner));
		boolean run = true;
		Date e = new Date();
		e.setHours(e.getHours() - 1);

		if (this.exp != null && this.exp.length != 0) {
			Node n = (Node) Serializer.get(exp);
			ResultSet rs1 = m.query(this.FeedName, n);// = QueryHelper.query(l,
			// a[0]);
			ArrayList<Result> list = new ArrayList<Result>(rs1.getResults()
					.values());
			Collections.sort(list);
			if (list.get(0).getTimestamp().after(this.lastrun)) {
				run = true;
			} else {
				run = false;
			}

		}

		TableDescriptor td = m.getTableDescriptor(FeedName);
		if (this.shouldRun() && run) {
			ResultSet rs = m.query(this.FeedName, 100);
			/*String retval = "Timestamp\t\t|\t\tValue\n";
			ArrayList<Result> l = new ArrayList<Result>(rs.getResults()
					.values());
			Collections.sort(l);
			for (int i = 0; i < l.size(); i++) {
				try {
					retval += l.get(i).getTimestamp() + "\t\t|\t\t"
							+ l.get(i).getValue(this.FeedName).getValue()
							+ "\n";
				} catch (Exception e1) {
				}
			}*/
			
			String retval = "Timestamp\t\t|\t\t";
			for(int i = 0; i<td.getStringmapper().size();i++) {
				retval +=td.getStringmapper().get(i) + "\t\t|\t\t";
			}
			retval += "\n";
			
			ArrayList<Result> l = new ArrayList<Result>(rs.getResults()
					.values());
			Collections.sort(l);
			for (int i = 0; i < l.size(); i++) {
				try {
					retval += l.get(i).getTimestamp() + "\t\t|\t\t";
					
					
					for(int j = 0; j<td.getStringmapper().size();j++) {
						retval +=l.get(i).getValue(td.getStringmapper().get(j)).getValue() + "\t\t|\t\t";
					}
							retval += "\n";
				} catch (Exception e1) {
				}
			}

			return retval;
		}

		return null;

	}

	private boolean shouldRun() {

		Date now = new Date();

		//String a[] = this.when.split(" ");
		boolean at = this.when != null;
		//String b = a[2];
		//String c[] = b.split(":");

		int MinsTrigger = 0;
		int HourTrigger = 0;

		if (at) {
			HourTrigger = Integer.parseInt(this.when.split(":")[0]);
			MinsTrigger = Integer.parseInt(this.when.split(":")[1]);
		}

		if (this.often.toString().equals("daily")) {
			if (((now.getTime() - this.lastrun.getTime()) > 86400000)
					&& ((now.getHours() == HourTrigger) && ((now.getMinutes() - MinsTrigger) <= 5))) {
				return true;
			}
		}

		if (this.often.toString().equals("hourly")) {
			if (((now.getTime() - this.lastrun.getTime()) > 3600000)
					&& ((now.getHours() == HourTrigger) && ((now.getMinutes() - MinsTrigger) <= 5))) {
				return true;
			}
		}

		if (this.often.toString().equals("every")) {
			int offset = this.rate;
			int multi = 0;
			if (this.timeunit.toString().equals("hours")) {
				multi = 3600000;
			} else if (this.timeunit.toString().equals("minutes")) {
				multi = 60000;
			} else if (this.timeunit.toString().equals("days")) {
				multi = 86400000;
			}

			if ((now.getTime() - this.lastrun.getTime()) > (offset * multi)) {
				return true;
			}

		}

		return false;
	}

	private Long getIdByName(String Name) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query1 = pm
				.newQuery("select from howl.parser.types.TableDescriptor where Name == '"
						+ Name
						+ "' "
						+ "import howl.parser.types.TableDescriptor;");

		List<TableDescriptor> result1 = (List<TableDescriptor>) query1
				.execute();
		if (result1.size() > 0) {
			return result1.get(0).getId();
		} else {
			return null;
		}
	}

	private String[] subArray(int start, int end, String[] s) {
		String[] ret = new String[end + 1 - start];
		for (int i = 0; i < end + 1 - start; i++) {
			ret[i] = s[start + i];
		}

		return ret;
	}

	/**
	 * @return the feedName
	 */
	public String getFeedName() {
		return FeedName;
	}

	/**
	 * @param feedName
	 *            the feedName to set
	 */
	public void setFeedName(String feedName) {
		FeedName = feedName;
	}


	/**
	 * @return the exp
	 */
	public byte[] getExp() {
		return exp;
	}

	/**
	 * @param exp
	 *            the exp to set
	 */
	public void setExp(byte[] exp) {
		this.exp = exp;
	}

	/**
	 * @return the timeunit
	 */
	public TIMEUNIT getTimeunit() {
		return timeunit;
	}

	/**
	 * @param timeunit the timeunit to set
	 */
	public void setTimeunit(TIMEUNIT timeunit) {
		this.timeunit = timeunit;
	}

	/**
	 * @return the often
	 */
	public OFTEN getOften() {
		return often;
	}

	/**
	 * @param often the often to set
	 */
	public void setOften(OFTEN often) {
		this.often = often;
	}

	/**
	 * @return the when
	 */
	public String getWhen() {
		return when;
	}

	/**
	 * @param when the when to set
	 */
	public void setWhen(String when) {
		this.when = when;
	}

	/**
	 * @return the rate
	 */
	public Integer getRate() {
		return rate;
	}

	/**
	 * @param rate the rate to set
	 */
	public void setRate(Integer rate) {
		this.rate = rate;
	}

}
